"//RayMarch.fx\n"
"//Performs ray marching and computes shadowed scattering\n"
"\n"
"#include \"BasicStructures.fxh\"\n"
"#include \"AtmosphereShadersCommon.fxh\"\n"
"\n"
"cbuffer cbParticipatingMediaScatteringParams\n"
"{\n"
"    AirScatteringAttribs g_MediaParams;\n"
"}\n"
"\n"
"cbuffer cbCameraAttribs\n"
"{\n"
"    CameraAttribs g_CameraAttribs;\n"
"}\n"
"\n"
"cbuffer cbLightParams\n"
"{\n"
"    LightAttribs g_LightAttribs;\n"
"}\n"
"\n"
"cbuffer cbPostProcessingAttribs\n"
"{\n"
"    EpipolarLightScatteringAttribs g_PPAttribs;\n"
"};\n"
"\n"
"cbuffer cbMiscDynamicParams\n"
"{\n"
"    MiscDynamicParams g_MiscParams;\n"
"}\n"
"\n"
"Texture2D<float2> g_tex2DOccludedNetDensityToAtmTop;\n"
"SamplerState      g_tex2DOccludedNetDensityToAtmTop_sampler;\n"
"\n"
"Texture2D<float>  g_tex2DEpipolarCamSpaceZ;\n"
"\n"
"#if ENABLE_LIGHT_SHAFTS\n"
"\n"
"#   if USE_1D_MIN_MAX_TREE\n"
"    Texture2D<float4> g_tex2DSliceUVDirAndOrigin;\n"
"    Texture2D<float2> g_tex2DMinMaxLightSpaceDepth;\n"
"#   endif\n"
"\n"
"Texture2DArray<float>  g_tex2DLightSpaceDepthMap;\n"
"SamplerComparisonState g_tex2DLightSpaceDepthMap_sampler;\n"
"\n"
"#endif\n"
"\n"
"Texture2D<float2> g_tex2DCoordinates;\n"
"\n"
"Texture2D<float>  g_tex2DCamSpaceZ;\n"
"SamplerState      g_tex2DCamSpaceZ_sampler;\n"
"\n"
"Texture2D<float4> g_tex2DColorBuffer;\n"
"\n"
"Texture2D<float>  g_tex2DAverageLuminance;\n"
"\n"
"Texture3D<float3> g_tex3DSingleSctrLUT;\n"
"SamplerState      g_tex3DSingleSctrLUT_sampler;\n"
"\n"
"Texture3D<float3> g_tex3DHighOrderSctrLUT;\n"
"SamplerState      g_tex3DHighOrderSctrLUT_sampler;\n"
"\n"
"Texture3D<float3> g_tex3DMultipleSctrLUT;\n"
"SamplerState      g_tex3DMultipleSctrLUT_sampler;\n"
"\n"
"\n"
"#include \"LookUpTables.fxh\"\n"
"#include \"ScatteringIntegrals.fxh\"\n"
"#include \"Extinction.fxh\"\n"
"#include \"UnshadowedScattering.fxh\"\n"
"#include \"ToneMapping.fxh\"\n"
"\n"
"\n"
"#if ENABLE_LIGHT_SHAFTS\n"
"// This function calculates inscattered light integral over the ray from the camera to \n"
"// the specified world space position using ray marching\n"
"float3 ComputeShadowedInscattering( in float2 f2RayMarchingSampleLocation,\n"
"                                    in float fRayEndCamSpaceZ,\n"
"                                    in float fCascadeInd,\n"
"                                    uint uiEpipolarSliceInd )\n"
"{   \n"
"    float3 f3CameraPos = g_CameraAttribs.f4Position.xyz;\n"
"    uint uiCascadeInd = uint(fCascadeInd);\n"
"    \n"
"    // Compute the ray termination point, full ray length and view direction\n"
"    float3 f3RayTermination = ProjSpaceXYZToWorldSpace( float3(f2RayMarchingSampleLocation, fRayEndCamSpaceZ), g_CameraAttribs.mProj, g_CameraAttribs.mViewProjInv );\n"
"    float3 f3FullRay = f3RayTermination - f3CameraPos;\n"
"    float fFullRayLength = length(f3FullRay);\n"
"    float3 f3ViewDir = f3FullRay / fFullRayLength;\n"
"\n"
"    float3 f3EarthCentre = g_PPAttribs.f4EarthCenter.xyz;\n"
"\n"
"    // Intersect the ray with the atmosphere boundaries:\n"
"    float4 f4Isecs;\n"
"    GetRaySphereIntersection2(f3CameraPos, f3ViewDir, f3EarthCentre, \n"
"                              float2(g_MediaParams.fAtmTopRadius, g_MediaParams.fAtmBottomRadius), f4Isecs);\n"
"    float2 f2RayAtmTopIsecs = f4Isecs.xy; \n"
"    float2 f2RayEarthIsecs  = f4Isecs.zw;\n"
"    \n"
"    if( f2RayAtmTopIsecs.y <= 0.0 )\n"
"    {\n"
"        //                                                          view dir\n"
"        //                                                        /\n"
"        //             d<0                                       /\n"
"        //               *--------->                            *\n"
"        //            .      .                             .   /  . \n"
"        //  .  \'                    \'  .         .  \'         /\\         \'  .\n"
"        //                                                   /  f2rayatmtopisecs.y < 0\n"
"        //\n"
"        // the camera is outside the atmosphere and the ray either does not intersect the\n"
"        // top of it or the intersection point is behind the camera. In either\n"
"        // case there is no inscattering\n"
"        return float3(0.0, 0.0, 0.0);\n"
"    }\n"
"\n"
"    // Restrict the camera position to the top of the atmosphere\n"
"    float fDistToAtmosphere = max(f2RayAtmTopIsecs.x, 0.0);\n"
"    float3 f3RestrainedCameraPos = f3CameraPos + fDistToAtmosphere * f3ViewDir;\n"
"\n"
"    // Limit the ray length by the distance to the top of the atmosphere if the ray does not hit terrain\n"
"    float fOrigRayLength = fFullRayLength;\n"
"    if( fRayEndCamSpaceZ > g_CameraAttribs.fFarPlaneZ ) // fFarPlaneZ is pre-multiplied with 0.999999f\n"
"        fFullRayLength = +FLT_MAX;\n"
"    // Limit the ray length by the distance to the point where the ray exits the atmosphere\n"
"    fFullRayLength = min(fFullRayLength, f2RayAtmTopIsecs.y);\n"
"\n"
"    // If there is an intersection with the Earth surface, limit the tracing distance to the intersection\n"
"    if( f2RayEarthIsecs.x > 0.0 )\n"
"    {\n"
"        fFullRayLength = min(fFullRayLength, f2RayEarthIsecs.x);\n"
"    }\n"
"\n"
"    fRayEndCamSpaceZ *= fFullRayLength / fOrigRayLength; \n"
"    \n"
"    float3 f3RayleighInscattering = float3(0.0, 0.0, 0.0);\n"
"    float3 f3MieInscattering = float3(0.0, 0.0, 0.0);\n"
"    float2 f2ParticleNetDensityFromCam = float2(0.0, 0.0);\n"
"    float3 f3RayEnd = float3(0.0, 0.0, 0.0), f3RayStart = float3(0.0, 0.0, 0.0);\n"
"    \n"
"    // Note that cosTheta = dot(DirOnCamera, LightDir) = dot(ViewDir, DirOnLight) because\n"
"    // DirOnCamera = -ViewDir and LightDir = -DirOnLight\n"
"    float cosTheta = dot(f3ViewDir, -g_LightAttribs.f4Direction.xyz);\n"
"    \n"
"    float fCascadeEndCamSpaceZ = 0.0;\n"
"    float fTotalLitLength = 0.0, fTotalMarchedLength = 0.0; // Required for multiple scattering\n"
"    float fDistToFirstLitSection = -1.0; // Used only in when SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT\n"
"    \n"
"#if CASCADE_PROCESSING_MODE == CASCADE_PROCESSING_MODE_SINGLE_PASS\n"
"    for(; uiCascadeInd < uint(g_PPAttribs.iNumCascades); ++uiCascadeInd, ++fCascadeInd)\n"
"#else\n"
"    for(int i=0; i<1; ++i)\n"
"#endif\n"
"    {\n"
"        float2 f2CascadeStartEndCamSpaceZ = g_LightAttribs.ShadowAttribs.Cascades[uiCascadeInd].f4StartEndZ.xy;\n"
"        float fCascadeStartCamSpaceZ = f2CascadeStartEndCamSpaceZ.x;//(uiCascadeInd > (uint)g_PPAttribs.iFirstCascadeToRayMarch) ? f2CascadeStartEndCamSpaceZ.x : 0;\n"
"        fCascadeEndCamSpaceZ = f2CascadeStartEndCamSpaceZ.y;\n"
"        \n"
"        // Check if the ray terminates before it enters current cascade \n"
"        if( fRayEndCamSpaceZ < fCascadeStartCamSpaceZ )\n"
"        {\n"
"            #if CASCADE_PROCESSING_MODE == CASCADE_PROCESSING_MODE_SINGLE_PASS\n"
"                break;\n"
"            #else\n"
"                return float3(0.0, 0.0, 0.0);\n"
"            #endif\n"
"        }\n"
"\n"
"        // Truncate the ray against the far and near planes of the current cascade:\n"
"        float fRayEndRatio = min( fRayEndCamSpaceZ, fCascadeEndCamSpaceZ ) / fRayEndCamSpaceZ;\n"
"        float fRayStartRatio = fCascadeStartCamSpaceZ / fRayEndCamSpaceZ;\n"
"        float fDistToRayStart = fFullRayLength * fRayStartRatio;\n"
"        float fDistToRayEnd   = fFullRayLength * fRayEndRatio;\n"
"\n"
"        // If the camera is outside the atmosphere and the ray intersects the top of it,\n"
"        // we must start integration from the first intersection point.\n"
"        // If the camera is in the atmosphere, first intersection point is always behind the camera \n"
"        // and thus is negative\n"
"        //                               \n"
"        //                      \n"
"        //                     \n"
"        //                   *                                              /\n"
"        //              .   /  .                                       .   /  . \n"
"        //    .  \'         /\\         \'  .                   .  \'         /\\         \'  .\n"
"        //                /  f2RayAtmTopIsecs.x > 0                      /  f2RayAtmTopIsecs.y > 0\n"
"        //                                                              *\n"
"        //                 f2RayAtmTopIsecs.y > 0                         f2RayAtmTopIsecs.x < 0\n"
"        //                /                                              /\n"
"        //\n"
"        fDistToRayStart = max(fDistToRayStart, f2RayAtmTopIsecs.x);\n"
"        fDistToRayEnd   = max(fDistToRayEnd,   f2RayAtmTopIsecs.x);\n"
"        \n"
"        // To properly compute scattering from the space, we must \n"
"        // set up ray end position before extiting the loop\n"
"        f3RayEnd   = f3CameraPos + f3ViewDir * fDistToRayEnd;\n"
"        f3RayStart = f3CameraPos + f3ViewDir * fDistToRayStart;\n"
"\n"
"        #if CASCADE_PROCESSING_MODE != CASCADE_PROCESSING_MODE_SINGLE_PASS\n"
"            float r = length(f3RestrainedCameraPos - f3EarthCentre);\n"
"            float fCosZenithAngle = dot(f3RestrainedCameraPos-f3EarthCentre, f3ViewDir) / r;\n"
"            float fDist = max(fDistToRayStart - fDistToAtmosphere, 0.0);\n"
"            f2ParticleNetDensityFromCam = GetDensityIntegralAnalytic(r, fCosZenithAngle, fDist, g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"        #endif\n"
"\n"
"        float fRayLength = fDistToRayEnd - fDistToRayStart;\n"
"        if( fRayLength <= 10.0 )\n"
"        {\n"
"            #if CASCADE_PROCESSING_MODE == CASCADE_PROCESSING_MODE_SINGLE_PASS\n"
"                continue;\n"
"            #else\n"
"                if( int(uiCascadeInd) == g_PPAttribs.iNumCascades-1 )\n"
"                    // We need to process remaining part of the ray\n"
"                    break;\n"
"                else\n"
"                    return float3(0.0, 0.0, 0.0);\n"
"            #endif\n"
"        }\n"
"\n"
"        // We trace the ray in the light projection space, not in the world space\n"
"        // Compute shadow map UV coordinates of the ray end point and its depth in the light space\n"
"        matrix mWorldToShadowMapUVDepth = g_LightAttribs.ShadowAttribs.mWorldToShadowMapUVDepth[uiCascadeInd];\n"
"        float3 f3StartUVAndDepthInLightSpace = WorldSpaceToShadowMapUV(f3RayStart, mWorldToShadowMapUVDepth);\n"
"        //f3StartUVAndDepthInLightSpace.z -= SHADOW_MAP_DEPTH_BIAS;\n"
"        float3 f3EndUVAndDepthInLightSpace = WorldSpaceToShadowMapUV(f3RayEnd, mWorldToShadowMapUVDepth);\n"
"        //f3EndUVAndDepthInLightSpace.z -= SHADOW_MAP_DEPTH_BIAS;\n"
"\n"
"        // Calculate normalized trace direction in the light projection space and its length\n"
"        float3 f3ShadowMapTraceDir = f3EndUVAndDepthInLightSpace.xyz - f3StartUVAndDepthInLightSpace.xyz;\n"
"        // If the ray is directed exactly at the light source, trace length will be zero\n"
"        // Clamp to a very small positive value to avoid division by zero\n"
"        float fTraceLenInShadowMapUVSpace = max( length( f3ShadowMapTraceDir.xy ), 1e-7 );\n"
"        // Note that f3ShadowMapTraceDir.xy can be exactly zero\n"
"        f3ShadowMapTraceDir /= fTraceLenInShadowMapUVSpace;\n"
"    \n"
"        float fShadowMapUVStepLen = 0.0;\n"
"        float2 f2SliceOriginUV = float2(0.0, 0.0);\n"
"        float2 f2SliceDirUV = float2(0.0, 0.0);\n"
"        uint uiMinMaxTexYInd = 0u;\n"
"\n"
"        #if USE_1D_MIN_MAX_TREE\n"
"        {\n"
"            // Get UV direction for this slice\n"
"            float4 f4SliceUVDirAndOrigin = g_tex2DSliceUVDirAndOrigin.Load( int3(uiEpipolarSliceInd,uiCascadeInd,0) );\n"
"            f2SliceDirUV = f4SliceUVDirAndOrigin.xy;\n"
"            //if( all(f4SliceUVDirAndOrigin == g_f4IncorrectSliceUVDirAndStart) )\n"
"            //{\n"
"            //    return float3(0,0,0);\n"
"            //}\n"
"            //return float3(f4SliceUVDirAndOrigin.xy,0);\n"
"            // Scale with the shadow map texel size\n"
"            fShadowMapUVStepLen = length(f2SliceDirUV);\n"
"            f2SliceOriginUV = f4SliceUVDirAndOrigin.zw;\n"
"         \n"
"            #if USE_COMBINED_MIN_MAX_TEXTURE\n"
"                uiMinMaxTexYInd = uiEpipolarSliceInd + (uiCascadeInd - uint(g_PPAttribs.iFirstCascadeToRayMarch)) * g_PPAttribs.uiNumEpipolarSlices;\n"
"            #else\n"
"                uiMinMaxTexYInd = uiEpipolarSliceInd;\n"
"            #endif\n"
"        }\n"
"        #else\n"
"        {\n"
"            //Calculate length of the trace step in light projection space\n"
"            float fMaxTraceDirDim = max( abs(f3ShadowMapTraceDir.x), abs(f3ShadowMapTraceDir.y) );\n"
"            fShadowMapUVStepLen = (fMaxTraceDirDim > 0.0) ? (g_PPAttribs.f2ShadowMapTexelSize.x / fMaxTraceDirDim) : 0.0;\n"
"            // Take into account maximum number of steps specified by the g_MiscParams.fMaxStepsAlongRay\n"
"            fShadowMapUVStepLen = max(fTraceLenInShadowMapUVSpace/g_MiscParams.fMaxStepsAlongRay, fShadowMapUVStepLen);\n"
"        }\n"
"        #endif\n"
"\n"
"        // Calcualte ray step length in world space\n"
"        float fRayStepLengthWS = fRayLength * (fShadowMapUVStepLen / fTraceLenInShadowMapUVSpace);\n"
"        // Note that fTraceLenInShadowMapUVSpace can be very small when looking directly at sun\n"
"        // Since fShadowMapUVStepLen is at least one shadow map texel in size, \n"
"        // fShadowMapUVStepLen / fTraceLenInShadowMapUVSpace >> 1 in this case and as a result\n"
"        // fRayStepLengthWS >> fRayLength\n"
"\n"
"        // March the ray\n"
"        float fDistanceMarchedInCascade = 0.0;\n"
"        float3 f3CurrShadowMapUVAndDepthInLightSpace = f3StartUVAndDepthInLightSpace.xyz;\n"
"\n"
"        // The following variables are used only if 1D min map optimization is enabled\n"
"        uint uiMinLevel = 0u;\n"
"        // It is essential to round initial sample pos to the closest integer\n"
"        uint uiCurrSamplePos = uint( length(f3StartUVAndDepthInLightSpace.xy - f2SliceOriginUV.xy)/fShadowMapUVStepLen + 0.5 );\n"
"        uint uiCurrTreeLevel = 0u;\n"
"        // Note that min/max shadow map does not contain finest resolution level\n"
"        // The first level it contains corresponds to step == 2\n"
"        int iLevelDataOffset = -int(g_PPAttribs.uiMinMaxShadowMapResolution);\n"
"        float fStepScale = 1.0;\n"
"        float fMaxStepScale = g_PPAttribs.fMaxShadowMapStep;\n"
"\n"
"        #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_INTEGRATION\n"
"        {\n"
"            // In order for the numerical integration to be accurate enough, it is necessary to make \n"
"            // at least 10 steps along the ray. To assure this, limit the maximum world step by \n"
"            // 1/10 of the ray length.\n"
"            // To avoid aliasing artifacts due to unstable sampling along the view ray, do this for\n"
"            // each cascade separately\n"
"            float fMaxAllowedWorldStepLen = fRayLength/10.0;\n"
"            fMaxStepScale = min(fMaxStepScale, fMaxAllowedWorldStepLen/fRayStepLengthWS);\n"
"        \n"
"            // Make sure that the world step length is not greater than the maximum allowable length\n"
"            if( fRayStepLengthWS > fMaxAllowedWorldStepLen )\n"
"            {\n"
"                fRayStepLengthWS = fMaxAllowedWorldStepLen;\n"
"                // Recalculate shadow map UV step len\n"
"                fShadowMapUVStepLen = fTraceLenInShadowMapUVSpace * fRayStepLengthWS / fRayLength;\n"
"                // Disable 1D min/max optimization. Note that fMaxStepScale < 1 anyway since \n"
"                // fRayStepLengthWS > fMaxAllowedWorldStepLen. Thus there is no real need to\n"
"                // make the max shadow map step negative. We do this just for clarity\n"
"                fMaxStepScale = -1.0;\n"
"            }\n"
"        }\n"
"        #endif\n"
"\n"
"        // Scale trace direction in light projection space to calculate the step in shadow map\n"
"        float3 f3ShadowMapUVAndDepthStep = f3ShadowMapTraceDir * fShadowMapUVStepLen;\n"
"        \n"
"        [loop]\n"
"        while( fDistanceMarchedInCascade < fRayLength )\n"
"        {\n"
"            // Clamp depth to a very small positive value to avoid z-fighting at camera location\n"
"            float fCurrDepthInLightSpace = max(f3CurrShadowMapUVAndDepthInLightSpace.z, 1e-7);\n"
"            float IsInLight = 0.0;\n"
"\n"
"            #if USE_1D_MIN_MAX_TREE\n"
"            {\n"
"                // If the step scale can be doubled without exceeding the maximum allowed scale and \n"
"                // the sample is located at the appropriate position, advance to the next coarser level\n"
"                if( 2.0*fStepScale < fMaxStepScale && ((uiCurrSamplePos & ((2u<<uiCurrTreeLevel)-1u)) == 0u) )\n"
"                {\n"
"                    iLevelDataOffset += int(g_PPAttribs.uiMinMaxShadowMapResolution >> uiCurrTreeLevel);\n"
"                    uiCurrTreeLevel++;\n"
"                    fStepScale *= 2.f;\n"
"                }\n"
"\n"
"                while(uiCurrTreeLevel > uiMinLevel)\n"
"                {\n"
"                    // Compute light space depths at the ends of the current ray section\n"
"\n"
"                    // What we need here is actually depth which is divided by the camera view space z\n"
"                    // Thus depth can be correctly interpolated in screen space:\n"
"                    // http://www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf\n"
"                    // A subtle moment here is that we need to be sure that we can skip fStepScale samples \n"
"                    // starting from 0 up to fStepScale-1. We do not need to do any checks against the sample fStepScale away:\n"
"                    //\n"
"                    //     --------------->\n"
"                    //\n"
"                    //          *\n"
"                    //               *         *\n"
"                    //     *              *     \n"
"                    //     0    1    2    3\n"
"                    //\n"
"                    //     |------------------>|\n"
"                    //        fStepScale = 4\n"
"                    float fNextLightSpaceDepth = f3CurrShadowMapUVAndDepthInLightSpace.z + f3ShadowMapUVAndDepthStep.z * (fStepScale-1.0);\n"
"                    float2 f2StartEndDepthOnRaySection = float2(f3CurrShadowMapUVAndDepthInLightSpace.z, fNextLightSpaceDepth);\n"
"                    f2StartEndDepthOnRaySection = f2StartEndDepthOnRaySection;//max(f2StartEndDepthOnRaySection, 1e-7);\n"
"\n"
"                    // Load 1D min/max depths\n"
"                    float2 f2CurrMinMaxDepth = g_tex2DMinMaxLightSpaceDepth.Load( int3( int(uiCurrSamplePos>>uiCurrTreeLevel) + iLevelDataOffset, uiMinMaxTexYInd, 0) );\n"
"                \n"
"                    IsInLight = ( f2StartEndDepthOnRaySection.x < f2CurrMinMaxDepth.x && \n"
"                                  f2StartEndDepthOnRaySection.y < f2CurrMinMaxDepth.x ) ? 1.f : 0.f;\n"
"                    bool bIsInShadow = f2StartEndDepthOnRaySection.x >= f2CurrMinMaxDepth.y && \n"
"                                       f2StartEndDepthOnRaySection.y >= f2CurrMinMaxDepth.y;\n"
"\n"
"                    if( IsInLight != 0.0 || bIsInShadow )\n"
"                        // If the ray section is fully lit or shadowed, we can break the loop\n"
"                        break;\n"
"                    // If the ray section is neither fully lit, nor shadowed, we have to go to the finer level\n"
"                    uiCurrTreeLevel--;\n"
"                    iLevelDataOffset -= int(g_PPAttribs.uiMinMaxShadowMapResolution >> uiCurrTreeLevel);\n"
"                    fStepScale /= 2.f;\n"
"                };\n"
"\n"
"                // If we are at the finest level, sample the shadow map with PCF\n"
"                [branch]\n"
"                if( uiCurrTreeLevel <= uiMinLevel )\n"
"                {\n"
"                    #ifdef GLSL\n"
"                        // There is no OpenGL counterpart for Texture2DArray.SampleCmpLevelZero()\n"
"                        IsInLight = g_tex2DLightSpaceDepthMap.SampleCmp( g_tex2DLightSpaceDepthMap_sampler, float3(f3CurrShadowMapUVAndDepthInLightSpace.xy,fCascadeInd), fCurrDepthInLightSpace  );\n"
"                    #else\n"
"                        // We cannot use SampleCmp() under flow control in HLSL\n"
"                        IsInLight = g_tex2DLightSpaceDepthMap.SampleCmpLevelZero( g_tex2DLightSpaceDepthMap_sampler, float3(f3CurrShadowMapUVAndDepthInLightSpace.xy,fCascadeInd), fCurrDepthInLightSpace  );\n"
"                    #endif\n"
"                }\n"
"            }\n"
"            #else\n"
"            {\n"
"                #ifdef GLSL\n"
"                    // There is no OpenGL counterpart for Texture2DArray.SampleCmpLevelZero()\n"
"                    IsInLight = g_tex2DLightSpaceDepthMap.SampleCmp( g_tex2DLightSpaceDepthMap_sampler, float3( f3CurrShadowMapUVAndDepthInLightSpace.xy, fCascadeInd ), fCurrDepthInLightSpace );\n"
"                #else\n"
"                    // We cannot use SampleCmp() under flow control in HLSL\n"
"                    IsInLight = g_tex2DLightSpaceDepthMap.SampleCmpLevelZero( g_tex2DLightSpaceDepthMap_sampler, float3( f3CurrShadowMapUVAndDepthInLightSpace.xy, fCascadeInd ), fCurrDepthInLightSpace );\n"
"                #endif\n"
"            }\n"
"            #endif\n"
"\n"
"            float fRemainingDist = max(fRayLength - fDistanceMarchedInCascade, 0.0);\n"
"            float fIntegrationStep = min(fRayStepLengthWS * fStepScale, fRemainingDist);\n"
"            float fIntegrationDist = fDistanceMarchedInCascade + fIntegrationStep/2.0;\n"
"\n"
"            #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_INTEGRATION\n"
"            {\n"
"                float3 f3CurrPos = f3RayStart + f3ViewDir * fIntegrationDist;\n"
"\n"
"                // Calculate integration point height above the SPHERICAL Earth surface:\n"
"                float3 f3EarthCentreToPointDir = f3CurrPos - f3EarthCentre;\n"
"                float fDistToEarthCentre = length(f3EarthCentreToPointDir);\n"
"                f3EarthCentreToPointDir /= fDistToEarthCentre;\n"
"                float fHeightAboveSurface = fDistToEarthCentre - g_MediaParams.fEarthRadius;\n"
"\n"
"                float2 f2ParticleDensity = exp( -float2(fHeightAboveSurface, fHeightAboveSurface) * g_MediaParams.f4ParticleScaleHeight.zw );\n"
"\n"
"                // Do not use this branch as it only degrades performance\n"
"                //if( IsInLight == 0)\n"
"                //    continue;\n"
"\n"
"                // Get net particle density from the integration point to the top of the atmosphere:\n"
"                float fCosSunZenithAngle = dot( f3EarthCentreToPointDir, -g_LightAttribs.f4Direction.xyz );\n"
"                float2 f2NetParticleDensityToAtmTop = GetNetParticleDensity(fHeightAboveSurface, fCosSunZenithAngle, g_MediaParams.fAtmBottomAltitude, g_MediaParams.fAtmAltitudeRangeInv);\n"
"        \n"
"                // Compute total particle density from the top of the atmosphere through the integraion point to camera\n"
"                float2 f2TotalParticleDensity = f2ParticleNetDensityFromCam + f2NetParticleDensityToAtmTop;\n"
"        \n"
"                // Update net particle density from the camera to the integration point:\n"
"                f2ParticleNetDensityFromCam += f2ParticleDensity * fIntegrationStep;\n"
"\n"
"                // Get optical depth\n"
"                float3 f3TotalRlghOpticalDepth = g_MediaParams.f4RayleighExtinctionCoeff.rgb * f2TotalParticleDensity.x;\n"
"                float3 f3TotalMieOpticalDepth  = g_MediaParams.f4MieExtinctionCoeff.rgb      * f2TotalParticleDensity.y;\n"
"        \n"
"                // And total extinction for the current integration point:\n"
"                float3 f3TotalExtinction = exp( -(f3TotalRlghOpticalDepth + f3TotalMieOpticalDepth) );\n"
"\n"
"                f2ParticleDensity *= fIntegrationStep * IsInLight;\n"
"                f3RayleighInscattering += f2ParticleDensity.x * f3TotalExtinction;\n"
"                f3MieInscattering      += f2ParticleDensity.y * f3TotalExtinction;\n"
"            }\n"
"            #endif\n"
"\n"
"            #if MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_OCCLUDED || SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT\n"
"                // Store the distance where the ray first enters the light\n"
"                fDistToFirstLitSection = (fDistToFirstLitSection < 0.0 && IsInLight > 0.0) ? fTotalMarchedLength : fDistToFirstLitSection;\n"
"            #endif\n"
"            f3CurrShadowMapUVAndDepthInLightSpace += f3ShadowMapUVAndDepthStep * fStepScale;\n"
"            uiCurrSamplePos += 1u << uiCurrTreeLevel; // int -> float conversions are slow\n"
"            fDistanceMarchedInCascade += fRayStepLengthWS * fStepScale;\n"
"\n"
"            #if MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_OCCLUDED || SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT\n"
"                fTotalLitLength += fIntegrationStep * IsInLight;\n"
"                fTotalMarchedLength += fIntegrationStep;\n"
"            #endif\n"
"        }\n"
"    }\n"
"\n"
"    #if MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_OCCLUDED || SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT\n"
"        // If the whole ray is in shadow, set the distance to the first lit section to the\n"
"        // total marched distance\n"
"        if( fDistToFirstLitSection < 0.0 )\n"
"            fDistToFirstLitSection = fTotalMarchedLength;\n"
"    #endif\n"
"\n"
"    float3 f3RemainingRayStart = float3(0.0, 0.0, 0.0);\n"
"    float fRemainingLength = 0.0;\n"
"    if( \n"
"#if CASCADE_PROCESSING_MODE != CASCADE_PROCESSING_MODE_SINGLE_PASS\n"
"        int(uiCascadeInd) == g_PPAttribs.iNumCascades-1 && \n"
"#endif\n"
"        fRayEndCamSpaceZ > fCascadeEndCamSpaceZ \n"
"       )\n"
"    {\n"
"        f3RemainingRayStart = f3RayEnd;\n"
"        f3RayEnd = f3CameraPos + fFullRayLength * f3ViewDir;\n"
"        fRemainingLength = length(f3RayEnd - f3RemainingRayStart);\n"
"        #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_INTEGRATION\n"
"        {\n"
"            // Do not allow integration step to become less than 50 km\n"
"            // Maximum possible view ray length is 2023 km (from the top of the\n"
"            // atmosphere touching the Earth and then again to the top of the \n"
"            // atmosphere).\n"
"            // For such ray, 41 integration step will be performed\n"
"            // Also assure that at least 20 steps are always performed\n"
"            float fMinStep = 50000.0;\n"
"            uint uiNumSteps = uint(max(20.0, ceil(fRemainingLength/fMinStep)));\n"
"            ComputeInsctrIntegral(f3RemainingRayStart,\n"
"                                  f3RayEnd,\n"
"                                  f3EarthCentre,\n"
"                                  g_MediaParams.fEarthRadius,\n"
"                                  g_MediaParams.fAtmBottomAltitude,\n"
"                                  g_MediaParams.fAtmAltitudeRangeInv,\n"
"                                  g_MediaParams.f4ParticleScaleHeight,\n"
"                                  -g_LightAttribs.f4Direction.xyz,\n"
"                                  uiNumSteps,\n"
"                                  f2ParticleNetDensityFromCam,\n"
"                                  f3RayleighInscattering,\n"
"                                  f3MieInscattering);\n"
"        }\n"
"        #endif\n"
"    }\n"
"\n"
"    float3 f3InsctrIntegral = float3(0.0, 0.0, 0.0);\n"
"\n"
"    #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_INTEGRATION\n"
"        // Apply phase functions\n"
"        // Note that cosTheta = dot(DirOnCamera, LightDir) = dot(ViewDir, DirOnLight) because\n"
"        // DirOnCamera = -ViewDir and LightDir = -DirOnLight\n"
"        ApplyPhaseFunctions(f3RayleighInscattering, f3MieInscattering, cosTheta);\n"
"\n"
"        f3InsctrIntegral = f3RayleighInscattering + f3MieInscattering;\n"
"    #endif\n"
"\n"
"    #if CASCADE_PROCESSING_MODE == CASCADE_PROCESSING_MODE_SINGLE_PASS\n"
"        // Note that the first cascade used for ray marching must contain camera within it\n"
"        // otherwise this expression might fail\n"
"        f3RayStart = f3RestrainedCameraPos;\n"
"    #endif\n"
"\n"
"    #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT || MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_OCCLUDED\n"
"    {\n"
"        #if MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_OCCLUDED\n"
"            #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT\n"
"                #define tex3DSctrLUT         g_tex3DMultipleSctrLUT\n"
"                #define tex3DSctrLUT_sampler g_tex3DMultipleSctrLUT_sampler\n"
"            #elif SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_NONE || SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_INTEGRATION\n"
"                #define tex3DSctrLUT         g_tex3DHighOrderSctrLUT\n"
"                #define tex3DSctrLUT_sampler g_tex3DHighOrderSctrLUT_sampler\n"
"            #endif\n"
"        #else\n"
"            #define tex3DSctrLUT         g_tex3DSingleSctrLUT\n"
"            #define tex3DSctrLUT_sampler g_tex3DSingleSctrLUT_sampler\n"
"        #endif\n"
"\n"
"        float3 f3MultipleScattering = float3(0.0, 0.0, 0.0);\n"
"        if( fTotalLitLength > 0.0 )\n"
"        {    \n"
"            float3 f3LitSectionStart = f3RayStart + fDistToFirstLitSection * f3ViewDir;\n"
"            float3 f3LitSectionEnd = f3LitSectionStart + fTotalLitLength * f3ViewDir;\n"
"\n"
"            float3 f3ExtinctionToStart = GetExtinctionUnverified(f3RestrainedCameraPos, f3LitSectionStart, f3ViewDir, f3EarthCentre,\n"
"                                                                 g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"            float4 f4UVWQ = float4(-1.0, -1.0, -1.0, -1.0);\n"
"            f3MultipleScattering = f3ExtinctionToStart *\n"
"                LookUpPrecomputedScattering(\n"
"                    f3LitSectionStart,\n"
"                    f3ViewDir,\n"
"                    f3EarthCentre,\n"
"                    g_MediaParams.fEarthRadius,\n"
"                    -g_LightAttribs.f4Direction.xyz,\n"
"                    g_MediaParams.fAtmBottomAltitude,\n"
"                    g_MediaParams.fAtmTopAltitude,\n"
"                    tex3DSctrLUT,\n"
"                    tex3DSctrLUT_sampler,\n"
"                    f4UVWQ); \n"
"        \n"
"            float3 f3ExtinctionToEnd = GetExtinctionUnverified(f3RestrainedCameraPos, f3LitSectionEnd, f3ViewDir,  f3EarthCentre,\n"
"                                                               g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"            // To avoid artifacts, we must be consistent when performing look-ups into the scattering texture, i.e.\n"
"            // we must assure that if the first look-up is above (below) horizon, then the second look-up\n"
"            // is also above (below) horizon.\n"
"            // We provide previous look-up coordinates to the function so that it is able to figure out where the first look-up\n"
"            // was performed\n"
"            f3MultipleScattering -= f3ExtinctionToEnd *\n"
"                LookUpPrecomputedScattering(\n"
"                    f3LitSectionEnd,\n"
"                    f3ViewDir,\n"
"                    f3EarthCentre,\n"
"                    g_MediaParams.fEarthRadius,\n"
"                    -g_LightAttribs.f4Direction.xyz,\n"
"                    g_MediaParams.fAtmBottomAltitude,\n"
"                    g_MediaParams.fAtmTopAltitude,\n"
"                    tex3DSctrLUT,\n"
"                    tex3DSctrLUT_sampler,\n"
"                    f4UVWQ);\n"
"        \n"
"            f3InsctrIntegral += max(f3MultipleScattering, float3(0.0, 0.0, 0.0));\n"
"        }\n"
"\n"
"        // Add contribution from the reminder of the ray behind the largest cascade\n"
"        if( fRemainingLength > 0.0 )\n"
"        {\n"
"            float3 f3Extinction = GetExtinctionUnverified(f3RestrainedCameraPos, f3RemainingRayStart, f3ViewDir, f3EarthCentre,\n"
"                                                          g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"            float4 f4UVWQ = float4(-1.0, -1.0, -1.0, -1.0);\n"
"            float3 f3RemainingInsctr = f3Extinction *\n"
"                LookUpPrecomputedScattering(\n"
"                    f3RemainingRayStart,\n"
"                    f3ViewDir,\n"
"                    f3EarthCentre,\n"
"                    g_MediaParams.fEarthRadius,\n"
"                    -g_LightAttribs.f4Direction.xyz,\n"
"                    g_MediaParams.fAtmBottomAltitude,\n"
"                    g_MediaParams.fAtmTopAltitude,\n"
"                    tex3DSctrLUT,\n"
"                    tex3DSctrLUT_sampler,\n"
"                    f4UVWQ);\n"
"        \n"
"            f3Extinction = GetExtinctionUnverified(f3RestrainedCameraPos, f3RayEnd, f3ViewDir, f3EarthCentre,\n"
"                                                   g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"            f3RemainingInsctr -= f3Extinction *\n"
"                LookUpPrecomputedScattering(\n"
"                    f3RayEnd,\n"
"                    f3ViewDir,\n"
"                    f3EarthCentre,\n"
"                    g_MediaParams.fEarthRadius,\n"
"                    -g_LightAttribs.f4Direction.xyz,\n"
"                    g_MediaParams.fAtmBottomAltitude,\n"
"                    g_MediaParams.fAtmTopAltitude,\n"
"                    tex3DSctrLUT,\n"
"                    tex3DSctrLUT_sampler,\n"
"                    f4UVWQ);\n"
"\n"
"            f3InsctrIntegral += max(f3RemainingInsctr, float3(0.0, 0.0, 0.0));\n"
"        }\n"
"    }\n"
"    #undef tex3DSctrLUT\n"
"    #undef tex3DSctrLUT_sampler\n"
"    #endif // #if SINGLE_SCATTERING_MODE == SINGLE_SCTR_MODE_LUT || MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_OCCLUDED\n"
"\n"
"    #if MULTIPLE_SCATTERING_MODE == MULTIPLE_SCTR_MODE_UNOCCLUDED\n"
"    {\n"
"        float3 f3HighOrderScattering = float3(0.0, 0.0, 0.0), f3Extinction = float3(0.0, 0.0, 0.0);\n"
"        \n"
"        float4 f4UVWQ = float4(-1.0, -1.0, -1.0, -1.0);\n"
"        f3Extinction = GetExtinctionUnverified(f3RestrainedCameraPos, f3RayStart, f3ViewDir, f3EarthCentre,\n"
"                                               g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"        f3HighOrderScattering += f3Extinction *\n"
"            LookUpPrecomputedScattering(\n"
"                f3RayStart,\n"
"                f3ViewDir,\n"
"                f3EarthCentre,\n"
"                g_MediaParams.fEarthRadius,\n"
"                -g_LightAttribs.f4Direction.xyz,\n"
"                g_MediaParams.fAtmBottomAltitude,\n"
"                g_MediaParams.fAtmTopAltitude,\n"
"                g_tex3DHighOrderSctrLUT,\n"
"                g_tex3DHighOrderSctrLUT_sampler,\n"
"                f4UVWQ); \n"
"        \n"
"        f3Extinction = GetExtinctionUnverified(f3RestrainedCameraPos, f3RayEnd, f3ViewDir, f3EarthCentre,\n"
"                                               g_MediaParams.fEarthRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"        // We provide previous look-up coordinates to the function so that it is able to figure out where the first look-up\n"
"        // was performed\n"
"        f3HighOrderScattering -= f3Extinction *\n"
"            LookUpPrecomputedScattering(\n"
"                f3RayEnd,\n"
"                f3ViewDir,\n"
"                f3EarthCentre,\n"
"                g_MediaParams.fEarthRadius,\n"
"                -g_LightAttribs.f4Direction.xyz,\n"
"                g_MediaParams.fAtmBottomAltitude,\n"
"                g_MediaParams.fAtmTopAltitude,\n"
"                g_tex3DHighOrderSctrLUT,\n"
"                g_tex3DHighOrderSctrLUT_sampler,\n"
"                f4UVWQ);\n"
"\n"
"        f3InsctrIntegral += f3HighOrderScattering;\n"
"    }\n"
"    #endif\n"
"\n"
"    return f3InsctrIntegral * g_LightAttribs.f4Intensity.rgb;\n"
"}\n"
"#endif\n"
"\n"
"\n"
"void RayMarchPS(in FullScreenTriangleVSOutput VSOut,\n"
"                out float4 f4Inscattering : SV_TARGET)\n"
"{\n"
"    uint2 ui2SamplePosSliceInd = uint2(VSOut.f4PixelPos.xy);\n"
"    float2 f2SampleLocation = g_tex2DCoordinates.Load( int3(ui2SamplePosSliceInd, 0) );\n"
"    float fRayEndCamSpaceZ = g_tex2DEpipolarCamSpaceZ.Load( int3(ui2SamplePosSliceInd, 0) );\n"
"\n"
"    [branch]\n"
"    if( any( Greater( abs( f2SampleLocation ), (1.0 + 1e-3) * float2(1.0, 1.0)) ) )\n"
"    {\n"
"        f4Inscattering = float4(0.0, 0.0, 0.0, 0.0);\n"
"        return;\n"
"    }\n"
"    f4Inscattering = float4(1.0, 1.0, 1.0, 1.0);\n"
"#if ENABLE_LIGHT_SHAFTS\n"
"    float fCascade = g_MiscParams.fCascadeInd + VSOut.fInstID;\n"
"    f4Inscattering.rgb = \n"
"        ComputeShadowedInscattering(f2SampleLocation, \n"
"                                    fRayEndCamSpaceZ,\n"
"                                    fCascade,\n"
"                                    ui2SamplePosSliceInd.y);\n"
"#else\n"
"    float3 f3Extinction;\n"
"    ComputeUnshadowedInscattering(f2SampleLocation,\n"
"                                  fRayEndCamSpaceZ,\n"
"                                  g_PPAttribs.uiInstrIntegralSteps,\n"
"                                  g_PPAttribs.f4EarthCenter.xyz,\n"
"                                  f4Inscattering.rgb,\n"
"                                  f3Extinction);\n"
"    f4Inscattering.rgb *= g_LightAttribs.f4Intensity.rgb;\n"
"#endif\n"
"}\n"
"\n"
"\n"
"//float3 FixInscatteredRadiancePS(FullScreenTriangleVSOutput VSOut) : SV_Target\n"
"//{\n"
"//    if( g_PPAttribs.bShowDepthBreaks )\n"
"//        return float3(0,1,0);\n"
"//\n"
"//    float fCascade = g_MiscParams.fCascadeInd + VSOut.fInstID;\n"
"//    float fRayEndCamSpaceZ = g_tex2DCamSpaceZ.SampleLevel( samLinearClamp, ProjToUV(VSOut.f2NormalizedXY.xy), 0 );\n"
"//\n"
"//#if ENABLE_LIGHT_SHAFTS\n"
"//    return ComputeShadowedInscattering(VSOut.f2NormalizedXY.xy, \n"
"//                              fRayEndCamSpaceZ,\n"
"//                              fCascade,\n"
"//                              false, // We cannot use min/max optimization at depth breaks\n"
"//                              0 // Ignored\n"
"//                              );\n"
"//#else\n"
"//    float3 f3Inscattering, f3Extinction;\n"
"//    ComputeUnshadowedInscattering(VSOut.f2NormalizedXY.xy, fRayEndCamSpaceZ, g_PPAttribs.uiInstrIntegralSteps, g_PPAttribs.f4EarthCenter.xyz, f3Inscattering, f3Extinction);\n"
"//    f3Inscattering *= g_LightAttribs.f4Intensity.rgb;\n"
"//    return f3Inscattering;\n"
"//#endif\n"
"//\n"
"//}\n"
"\n"
"\n"
"void FixAndApplyInscatteredRadiancePS(FullScreenTriangleVSOutput VSOut,\n"
"                                      out float4 f4Color : SV_Target)\n"
"{\n"
"    f4Color = float4(0.0, 1.0, 0.0, 1.0);\n"
"    if( g_PPAttribs.bShowDepthBreaks )\n"
"        return;\n"
"\n"
"    float fCamSpaceZ = g_tex2DCamSpaceZ.SampleLevel(g_tex2DCamSpaceZ_sampler, NormalizedDeviceXYToTexUV(VSOut.f2NormalizedXY), 0 );\n"
"    float3 f3BackgroundColor = float3(0.0, 0.0, 0.0);\n"
"    [branch]\n"
"    if( !g_PPAttribs.bShowLightingOnly )\n"
"    {\n"
"        f3BackgroundColor = g_tex2DColorBuffer.Load( int3(VSOut.f4PixelPos.xy,0) ).rgb;\n"
"        f3BackgroundColor *= (fCamSpaceZ > g_CameraAttribs.fFarPlaneZ) ? g_LightAttribs.f4Intensity.rgb : float3(1.0, 1.0, 1.0);\n"
"        float3 f3ReconstructedPosWS = ProjSpaceXYZToWorldSpace(float3(VSOut.f2NormalizedXY.xy, fCamSpaceZ), g_CameraAttribs.mProj, g_CameraAttribs.mViewProjInv);\n"
"        float3 f3Extinction = GetExtinction(g_CameraAttribs.f4Position.xyz, f3ReconstructedPosWS, g_PPAttribs.f4EarthCenter.xyz,\n"
"                                            g_MediaParams.fAtmBottomRadius, g_MediaParams.fAtmTopRadius, g_MediaParams.f4ParticleScaleHeight);\n"
"        f3BackgroundColor *= f3Extinction.rgb;\n"
"    }\n"
"    \n"
"    float fCascade = g_MiscParams.fCascadeInd + VSOut.fInstID;\n"
"\n"
"#if ENABLE_LIGHT_SHAFTS\n"
"    float3 f3InsctrColor = \n"
"        ComputeShadowedInscattering(VSOut.f2NormalizedXY.xy, \n"
"                              fCamSpaceZ,\n"
"                              fCascade,\n"
"                              0u // Ignored\n"
"                              );\n"
"#else\n"
"    float3 f3InsctrColor, f3Extinction;\n"
"    ComputeUnshadowedInscattering(VSOut.f2NormalizedXY.xy,\n"
"                                  fCamSpaceZ,\n"
"                                  g_PPAttribs.uiInstrIntegralSteps,\n"
"                                  g_PPAttribs.f4EarthCenter.xyz,\n"
"                                  f3InsctrColor,\n"
"                                  f3Extinction);\n"
"    f3InsctrColor *= g_LightAttribs.f4Intensity.rgb;\n"
"#endif\n"
"\n"
"    f4Color.rgb = (f3BackgroundColor + f3InsctrColor);\n"
"#if PERFORM_TONE_MAPPING\n"
"    float fAveLogLum = GetAverageSceneLuminance(g_tex2DAverageLuminance);\n"
"    f4Color.rgb = ToneMap(f3BackgroundColor + f3InsctrColor, g_PPAttribs.ToneMapping, fAveLogLum);\n"
"#else\n"
"    const float MinLumn = 0.01;\n"
"    float2 LogLum_W = GetWeightedLogLum(f3BackgroundColor + f3InsctrColor, MinLumn);\n"
"    f4Color.rgb = float3(LogLum_W.x, LogLum_W.y, 0.0);\n"
"#endif\n"
"}\n"
